LL_I2C_Init and LL_I2C_DeInit APIs migration

The LL initialization and de-initialization functions previously available in the stm32tnxx_ll_i2c.c files within HAL1 are no longer present in HAL2. In HAL2, all LL C files ( stm32tnxx_ll_i2c.c) have been removed, leaving only the LL header files ( stm32tnxx_ll_i2c.h) that contain static inline functions.

If users need to initialize or de-initialize I2C using the LL layer, they have two methods:

  • Utilize STM32CubeMX2 Code Generation: Rely on STM32CubeMX2 to generate code with the LL layer for I2C initialization and de-initialization.

  • Replace manually the initialization and de-initialization functionsReplace the LL_I2C_Init and LL_I2C_DeInit functions

    manually with equivalent sequences using the static inline functions provided in the stm32tnxx_ll_i2c.h file, tailored to their specific configuration and requirements.

This approach ensures that the initialization and de-initialization sequences are precisely addressing the given use case based on the LL static inline functions provided in the stm32tnxx_ll_i2c.h header file. The sequences offer improved footprint optimization compared to the previous LL initialization functions found in stm32tnxx_ll_i2c.c.

Related concept: Remove stm32tnxx_ll_ppp.c files

Method 1: Utilize STM32CubeMX2 Code Generation

LL I2C configuration panel

Create a new project with the STM32CubeMX2, then start the initialization and the main configuration.

Example Image

LL I2C main features configuration

Configure the I2C main features

Example Image

LL I2C advanced features configuration

Configure the advanced features of the I2C if needed

Example Image

LL I2C GPIO configuration

Configure the GPIOs needed by the I2C

Example Image

LL I2C NVIC configuration

Configure the NVIC if the application requires the I2C interrupts

Example Image

LL I2C DMA configuration

Configure the I2C DMA(s) if the application requires to use the I2C in DMA mode

Example Image

Generated I2C initialization sequence

The I2C initialization and de-initialization sequences are generated in the mx_i2c1_init and mx_i2c1_deinit functions in mx_i2c1.c file under $YOUR_PROJECT_NAME$/$YOUR_PROJECT_NAME$_SW/generated/STM32Cube_CodeGen.

STM32CubeMX2 Generated : I2C initialization sequence

Topic

Code Snippet HAL1

Code Snippet HAL2

Init and config sequence function

static void MX_I2C1_Init(void)
{
   LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);

   LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
   LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
   LL_I2C_EnableAutoEndMode(I2C1);
   LL_I2C_EnableOwnAddress2(I2C1);
   LL_I2C_EnableGeneralCall(I2C1);
   LL_I2C_EnableClockStretching(I2C1);
   LL_I2C_Enable_SelectedTrigger(I2C1);
   LL_I2C_SetSelectedTrigger(I2C1, LL_I2C_GRP1_GPDMA_CH0_TCF_TRG);
   LL_I2C_SetTriggerPolarity(I2C1, LL_I2C_TRIG_POLARITY_RISING);
   }

   static void MX_GPDMA1_Init(void)
   {
   LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPDMA1);
   }

   static void MX_GPIO_Init(void)
   {
   LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

}
I2C_TypeDef *mx_i2c1_init(void)
{
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);

 /*
    Timing automatically calculated with:
    - I2C1 input clock at 160000000 Hz
    - I2C clock speed at 100000 Hz
 */
  LL_I2C_SetTiming(I2C1, 0x80D25052);
  LL_I2C_ConfigOwnAddress1(I2C1, 0 << 1U, LL_I2C_OWNADDRESS1_7BIT);
  LL_I2C_SetMasterAddressingMode(I2C1, LL_I2C_ADDRESSING_MODE_7BIT);
  LL_I2C_WRITE_REG(I2C1, CR2, (LL_I2C_READ_REG(I2C1, CR2) | I2C_CR2_AUTOEND | I2C_CR2_NACK));

  LL_I2C_SetOwnAddress2(I2C1, undefined, LL_I2C_OWNADDRESS2_);
  LL_I2C_EnableOwnAddress2(I2C1);

  LL_I2C_EnableFastModePlus(I2C1);

  LL_I2C_EnableWakeUpFromStop(I2C1);

  LL_I2C_EnableGeneralCall(I2C1);

  LL_I2C_SetConfigAutonomousModeTrigger(I2C1, LL_I2C_TRIG_GRP1_, LL_I2C_TRIG_POLARITY_RISING);;
  LL_I2C_Enable_SelectedTrigger(I2C1);

  LL_I2C_Enable(I2C1);

  /* GPIO Clocks activation */
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPDMA1);
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPDMA1);

  LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);

  return I2C1;
}

Deinit sequence function

void MX_I2C1_DeInit(void)
{
  if (LL_I2C_DeInit(I2C1) != HAL_OK)
  {
    Error_Handler();
  }
}
void mx_i2c1_deinit(void)
{
  LL_I2C_Disable(I2C1);

  LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
  LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
  LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C1);
  LL_DMA_DisableChannel(GPDMA1_CH0);
  LL_DMA_ClearFlag(GPDMA1_CH0, LL_DMA_FLAG_ALL);
  LL_DMA_DisableChannel(GPDMA1_CH1);
  LL_DMA_ClearFlag(GPDMA1_CH1, LL_DMA_FLAG_ALL);
}

Method 2: Replace manually the initialization and de-initialization functions

LL_I2C_Init() API migration

According to the use-case, implement the precise sequence call based on the LL static inline functions provided in the stm32tnxx_ll_i2c.h header file.

I2C Mode Comparison between HAL1 and HAL2

HAL1

HAL2

Case of enable OwnAddress1

LL_I2C_InitTypeDef i2c_InitStruct;

i2c_InitStruct.PeripheralMode  = LL_I2C_MODE_I2C;
i2c_InitStruct.AnalogFilter    = LL_I2C_ANALOGFILTER_ENABLE;
i2c_InitStruct.DigitalFilter   = 0U;
i2c_InitStruct.OwnAddress1     = 90;
i2c_InitStruct.Timing          = 0x10B046E2;
i2c_InitStruct.TypeAcknowledge = LL_I2C_NACK;
i2c_InitStruct.OwnAddrSize     = LL_I2C_OWNADDRESS1_7BIT;
LL_I2C_Init(I2C1, &i2c_InitStruct);
LL_I2C_Disable(I2C1);
LL_I2C_ConfigFilters(I2C1, LL_I2C_ANALOGFILTER_ENABLE, 0U);
LL_I2C_SetTiming(I2C1, 0x10B046E2);
LL_I2C_Enable(I2C1);
LL_I2C_DisableOwnAddress1(I2C1);
LL_I2C_SetOwnAddress1(I2C1, 0U, LL_I2C_OWNADDRESS1_7BIT);
LL_I2C_EnableOwnAddress1(I2C1);
LL_I2C_SetMode(I2C1, LL_I2C_MODE_I2C);
LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_NACK);

Case of disable OwnAddress1

LL_I2C_InitTypeDef i2c_InitStruct;

i2c_InitStruct.PeripheralMode  = LL_I2C_MODE_I2C;
i2c_InitStruct.AnalogFilter    = LL_I2C_ANALOGFILTER_ENABLE;
i2c_InitStruct.DigitalFilter   = 0U;
i2c_InitStruct.OwnAddress1     = 90;
i2c_InitStruct.Timing          = 0x10B046E2;
i2c_InitStruct.TypeAcknowledge = LL_I2C_NACK;
i2c_InitStruct.OwnAddrSize     = LL_I2C_OWNADDRESS1_7BIT;
LL_I2C_Init(I2C1, &i2c_InitStruct);
LL_I2C_Disable(I2C1);
LL_I2C_ConfigFilters(I2C1, LL_I2C_ANALOGFILTER_ENABLE, 0U);
LL_I2C_SetTiming(I2C1, 0x10B046E2);
LL_I2C_Enable(I2C1);
LL_I2C_SetMode(I2C1, LL_I2C_MODE_I2C);
LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_NACK);

LL_I2C_DeInit() API migration

According to the used I2C1, Implement the precise calls to LL_APB1_GRP1_ForceReset() and LL_APB1_GRP1_ReleaseReset()

Comparison of HAL1 and HAL2

HAL1

HAL2

LL_I2C_DeInit(I2C1)
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);